package lesson2.example2;

import java.util.EnumSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.processing.Messager;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.ElementScanner7;
import javax.tools.Diagnostic.Kind;

public class NameCheckScanner extends ElementScanner7<Void, Void> {

	private final Messager messager;

	public NameCheckScanner(Messager messager) {
		this.messager = messager;
	}

	@Override
	public Void visitType(TypeElement e, Void p) {
		scan(e.getTypeParameters(), p);
		checkName(e,"[A-Z][A-Za-z0-9]{0,}","类名%s不符合驼式命名法\n");
		super.visitType(e, p);
		return null;
	}

	public void checkName(Element e,String regEx,String info) {
		String name = e.getSimpleName().toString();
		Pattern pattern = Pattern.compile(regEx);
		Matcher matcher = pattern.matcher(name);
		if (!matcher.matches()) {
			messager.printMessage(Kind.WARNING,System.out.format(info,name).toString() , e);
		}
	}

	@Override
	public Void visitExecutable(ExecutableElement e, Void p) {
		if (e.getKind() == ElementKind.METHOD) {
			checkName(e,"[a-z][A-Za-z0-9]{0,}","方法%s不符合符合驼式命名法，首字母小写\n");
		}
		super.visitExecutable(e, p);
		return null;
	}

	@Override
	public Void visitVariable(VariableElement e, Void p) {
		// 如果这个Variable是枚举或常量，则按大写命名检查，否则按照驼式命名法规则检查
		if (e.getKind() == ElementKind.ENUM_CONSTANT ||
				e.getConstantValue() != null ||
				heuristicallyConstant(e))
			checkName(e,"[A-Z][A-Z_]{0,}","常量%s不符合要求全部大写字母或下划线构成，并且第一个字符不能是下划线\n");
		else
			checkName(e,"[a-z][A-Za-z0-9]{0,}","变量%s不符合符合驼式命名法，首字母小写\n");
		return null;
	}

	private boolean heuristicallyConstant(VariableElement e) {
		if (e.getEnclosingElement().getKind() == ElementKind.INTERFACE)
			return true;
		else if (e.getKind() == ElementKind.FIELD
				&& e.getModifiers().containsAll(EnumSet.of(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)))
			return true;
		else {
			return false;
		}
	}
}



